/*
 * $Log: AgentWorldModelLayer.java,v $ Revision 1.11 2006/11/05 13:57:59 wetzker
 * more merging - CLang + MF + some states still missing
 * 
 * Revision 1.10.4.2 2006/10/25 14:33:36 endert Latest SoccerScope Version plus
 * Database ability
 * 
 * Revision 1.9.2.6 2006/08/10 12:42:21 benjaboe Teammates and Opponents can
 * activated for the the AgentWorldModelLayer seperately. BestPosition will be
 * placed by teammates only. (Prophet calculates only these)
 * 
 * Revision 1.9.2.5 2006/07/31 13:48:58 benjaboe Connection from Agent is named
 * comprehensible
 * 
 * Revision 1.9.2.4 2006/07/29 13:32:42 benjaboe Some parts of the
 * AgentModelLayer can be activated/deactivated. The drawing does not use the
 * LocalScene any more - LocalScene is deleted.
 * 
 * Revision 1.9.2.3 2006/07/02 15:41:36 benjaboe AgentWorldModel is shown for
 * both Team if possible
 * 
 * Revision 1.9.2.2 2006/06/26 14:19:11 benjaboe Player get his own
 * PlayerWorldModel. No NullPointerExceptions when Player has no
 * PlayerWorldModel.
 * 
 * Revision 1.9.2.1 2006/06/26 07:04:24 benjaboe Datamodell umgebaut
 * 
 * Revision 1.9 2006/05/21 15:32:28 gamel show positioning
 * 
 * Revision 1.8.4.1 2006/05/21 15:25:13 gamel new positioning
 * 
 * Revision 1.8 2006/05/05 17:01:02 wetzker best positions are know shown in gui
 * 
 * Revision 1.7 2006/04/18 22:46:31 wetzker merged with situationEvaluation
 * branch new: - central situation evaluation for states with ball control -
 * kickNRun situation - ball interception possible when ball kickable - role
 * model for players 6-11(roles are shown in gui, roles not used much for acting
 * yet)
 * 
 * Revision 1.6 2006/04/18 00:28:01 endert PointTo Ready, OpponentAnalyzer fixed
 * and GUI updated!
 * 
 * Revision 1.5 2006/04/17 12:47:02 endert Point the Stamina, and diplay in
 * AgentWM in SoccerScope
 * 
 * Revision 1.4.2.1 2006/04/18 21:59:34 wetzker added role model for players
 * 6-11 improved evaluation function
 * 
 * Revision 1.4 2006/04/05 22:48:01 wetzker added prediction of other players
 * state each player now contains a stateEvaluation (see StateTactic) used the
 * prediction for calculation the players of the next cycle (can be seen in the
 * gui) + new State (OpponentBallInterception) for prediction of opponents
 * removed bug in delayed intercetion (cause stamina loss for nothing)
 * meta_playmodes can be used now (added always playmode) improved attack in
 * line
 * 
 * Revision 1.3 2006/03/27 23:25:54 wetzker simplified stateEvaluation - moved
 * most of SimpleState into Abstract - moved most of StateEvaluation into
 * StateTactic adapted GUIUpdate - deleted state tables - only 1 state update
 * each cycle - gui should now be much faster (less holes)
 * 
 * Revision 1.2 2006/03/22 23:38:21 wetzker cleaned gui connection - wm is now
 * only send after an action - added more say + attentionTo logic set dribble
 * state value -20 percent for nightly tournament added state memory to LTM
 * 
 * Revision 1.1 2006/03/13 07:37:40 axle moved from ROOT/src for Maven 2
 * Buildsystem and Team/Soccerscope separation
 * 
 * Revision 1.19 2006/03/07 12:46:21 endert Merge after refactoring: - New
 * State-Interface: One Method for each action type - Action Bean removed -
 * ActionFactorys for helper methods, States calculate main-Action themselves -
 * formatted code - added State-List in Monitor (Context-Menu of Player) - other
 * smaller stuff
 * 
 * Revision 1.18.2.1 2006/02/25 22:07:03 wetzker formated
 * 
 * Revision 1.18 2006/02/22 16:05:00 endert This is done: - Rebound SoccerScope
 * to Agents (can be added or removed in config-file) - Situations now all
 * extend abstract class Situation - Refactorings: ActionBean _ removed from
 * Attributes - SoccerScope will automatically connect to host given in
 * Start-Call - Trainer uses the same host as soccerscope - Removed unused stuff
 * (old confs, bat, etc.) - Code formatted (good luck when merging) - organized
 * imports - all that i forgot to mention here
 * 
 * Revision 1.17 2005/10/25 20:51:35 endert Added Training-Editor to
 * SoccerScope, restructuring in some old classes and some experimental stuff
 * (goals, commitments, mental model)
 * 
 * Revision 1.16.4.1 2005/10/10 11:05:07 endert New Training-Scenario Editor!
 * There exists a dialog, which opens on middle-mouse click on the field. From
 * here, the Trainings-Scenario may be specified in a more comfortable manner.
 * The Trainings-Scenario is also visualized on the Field - using the
 * TrainingModelLayer. The TrainingModel itself contains all data specified in
 * the scenario, and therefor can be serialized to HDD, using an XML-Stream
 * generator (XStream). The Scenario editor is still under development.
 * 
 * Revision 1.16 2005/10/01 13:46:17 wetzker organized playersmodel and removed
 * all unsed methods - redifined offside as the y-coordinate of the last
 * opponent but the goalie added predicted interception time to gui added new
 * dashToPoint-version with given time for reaching point added dynamic-depth to
 * pass calculation as it seems very time consuming improved collision with ball
 * model
 * 
 * Revision 1.15 2005/09/01 17:30:32 thyrion added quick'n'dirty display of
 * opponentinterceptionpoint
 * 
 * Revision 1.14 2005/09/01 08:29:08 andpaul added: showing actual player state
 * in WorldModelLayer (on the right site of the playing field)
 * 
 * Revision 1.13 2005/08/16 16:26:49 wetzker merged composite branch
 * 
 * Revision 1.11.2.6 2005/08/16 15:43:29 wetzker removed ball and player cloning
 * in getSelf, getBall -> should be much faster now merged with changes from
 * head
 * 
 * Revision 1.11.2.5 2005/07/20 17:59:02 wetzker new StateValues, AB +
 * fastDribbling (by now only in BodyDir), + started InterceptBallSituation
 * 
 * Revision 1.11.2.4 2005/07/18 09:00:07 wetzker debugged: - shootGoal, now
 * working quiet well (but still only a workaround) - attackInLine - bodyCycle()
 * was wrong :/ - dribbling added: - stamina management, use
 * p.correctDashPower(StaminaLevel) moved: - ControllerNumbers, as they aren't
 * use solo by the connection
 * 
 * Revision 1.11.2.3 2005/07/15 19:53:45 wetzker added offside line
 * 
 * Revision 1.11.2.2 2005/07/15 19:19:38 wetzker debugged NPE
 * 
 * Revision 1.11.2.1 2005/07/14 16:53:53 wetzker + speed in AgentWM is displayed
 * 
 * Revision 1.11 2005/07/04 17:10:42 thyrion workaround if cycle < 0
 * 
 * Revision 1.10 2005/06/24 21:29:37 wetzker changes in Agent.WM.Visualization -
 * shadows now got numbers - goalies differ in color
 * 
 * Revision 1.9 2005/06/20 22:21:18 andpaul added: show and save body direction
 * of wm players
 * 
 * Revision 1.8 2005/06/20 21:57:47 andpaul added: store and show reliable flag
 * 
 * Revision 1.7 2005/06/19 23:40:50 wetzker added IP
 * 
 * Revision 1.6 2005/06/19 19:44:37 till added parameter teamSide to constructor
 * of soccerscope.model.Player
 * 
 * Revision 1.5 2005/06/15 18:14:33 haeder removed unused imports
 * 
 * Revision 1.4 2005/06/15 17:03:38 wetzker removed JIAC from Head + changes in
 * framework please report bugs or shortcomings some scenarios might not work
 * because of wrong imports
 * 
 * Revision 1.2.2.1 2005/06/15 16:45:01 wetzker final version
 * 
 * Revision 1.3 2005/06/12 18:52:17 thyrion fixed saving&loading of our
 * worldmodel (to load first open server log)
 * 
 * Revision 1.2 2005/05/19 15:35:26 wetzker + IP shown in GUI (use AgentWM)
 * 
 * Revision 1.1 2005/04/20 10:38:40 endert Fresh Team Repository installation
 * from /home/e/endert/Robocup to here.
 * 
 * Revision 1.3 2005/02/06 07:20:08 maketi Added soccerscope with connection to
 * our world model
 * 
 * Revision 1.3 2002/10/10 09:43:40 koji ͥ*�ΰ�η׻��β���
 * (Direction-Distance Table)
 * 
 * Revision 1.2 2002/10/04 10:39:23 koji
 * Tuple,Point,Vector�Υѥå������ѹ���Geometry,Circle,Line,Rectangle�ɲ�
 * 
 * Revision 1.1 2002/10/01 14:11:13 koji support Preference, gif format
 * 
 * Revision 1.3 2002/09/12 15:28:32 koji
 * ������%����?���ɲ�,ColorTool��Color2�����
 * 
 * Revision 1.2 2002/09/02 07:06:29 taku-ako
 * Geometry��Ϣ�Υ饤�֥����.
 * 
 * Revision 1.1.1.1 2002/03/01 14:12:53 koji CVS�����
 * 
 */

package soccerscope.view.layer;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JToggleButton;

import robocup.component.tactics.AbstractState.STATES;
import soccerscope.model.ClientScene;
import soccerscope.model.ColorDB;
import soccerscope.model.HeteroParam;
import soccerscope.model.Param;
import soccerscope.model.PlayerWorldModel;
import soccerscope.model.SimplePlayer;
import soccerscope.model.SoccerObjectID;
import soccerscope.model.WorldModel;
import soccerscope.util.geom.Point2f;
import soccerscope.util.geom.Tuple2f;
import soccerscope.view.FieldPane;
import soccerscope.view.SoccerObjectSelectObserver;

public class AgentWorldModelLayer
    extends Layer
    implements SoccerObjectSelectObserver, SoccerObjectID,
    LayerBooleanObserver, ActionListener {

  public final static String SETS_ALL_ON_TEXT  = "Sets all on";
  public final static String SETS_ALL_OFF_TEXT = "Sets all off";

  private LayerBoolean       onCB;

  private LayerBoolean       teammatesCB;
  private LayerBoolean       nextTeammateCB;
  private LayerBoolean       opponentCB;
  private LayerBoolean       nextOpponentCB;

  private LayerBoolean       playerCB;

  private LayerBoolean       bestPosCB;

  private LayerBoolean       ballCB;

  private LayerBoolean       ipCB;

  private LayerBoolean       oppIPCB;

  private LayerBoolean       velocityCB;

  private LayerBoolean       offsideLineCB;

  private LayerBoolean       staminaCB;

  private JMenuItem          allMenu;

  public AgentWorldModelLayer(
      FieldPane fieldPane,
      boolean enable) {

    super(fieldPane, enable);

    this.onCB = new LayerBoolean("Layer on", this.enable);
    this.onCB.addObserver(new AgentWorldModelLayerToggleListener());

    this.teammatesCB = new LayerBoolean("Teammates", true);
    this.teammatesCB.addObserver(this);
    this.nextTeammateCB = new LayerBoolean("NextTeammates", false);
    this.nextTeammateCB.addObserver(this);
    this.opponentCB = new LayerBoolean("Opponents", true);
    this.opponentCB.addObserver(this);
    this.nextOpponentCB = new LayerBoolean("NextOpponents", false);
    this.nextOpponentCB.addObserver(this);

    this.playerCB = new LayerBoolean("Players", true);
    this.playerCB.addObserver(this);
    this.bestPosCB = new LayerBoolean("Best Position", true);
    this.bestPosCB.addObserver(this);
    this.ballCB = new LayerBoolean("Ball", true);
    this.ballCB.addObserver(this);
    this.ipCB = new LayerBoolean("Ball intercept point", false);
    this.ipCB.addObserver(this);
    this.oppIPCB = new LayerBoolean("Opponent intercept point", false);
    this.oppIPCB.addObserver(this);
    this.velocityCB = new LayerBoolean("Velocity", false);
    this.velocityCB.addObserver(this);
    this.offsideLineCB = new LayerBoolean("Offside line", true);
    this.offsideLineCB.addObserver(this);
    this.staminaCB = new LayerBoolean("Staminas", false);
    this.staminaCB.addObserver(this);
  }

  @Override
  public String getLayerName() {

    return "AgentWorldModel";
  }

  @Override
  public JPanel getConfigPanel() {

    JPanel panel = new JPanel();

    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    panel.add(this.teammatesCB.getCheckBox());
    panel.add(this.nextTeammateCB.getCheckBox());
    panel.add(this.opponentCB.getCheckBox());
    panel.add(this.nextOpponentCB.getCheckBox());

    panel.add(this.playerCB.getCheckBox());
    panel.add(this.bestPosCB.getCheckBox());
    panel.add(this.ballCB.getCheckBox());
    panel.add(this.ipCB.getCheckBox());
    panel.add(this.oppIPCB.getCheckBox());
    panel.add(this.velocityCB.getCheckBox());
    panel.add(this.offsideLineCB.getCheckBox());
    panel.add(this.staminaCB.getCheckBox());

    return panel;
  }

  @Override
  public JToggleButton createJToggleButton() {

    JToggleButton button = this.onCB.getToggleButton();
    return button;
  }

  private class AgentWorldModelLayerToggleListener
      implements LayerBooleanObserver {

    /**
     * is called when a bool has changed.
     */
    public void boolChanged() {

      AgentWorldModelLayer.this.enable = AgentWorldModelLayer.this.onCB
          .getValue();
    }
  }

  @Override
  public JMenu createJCheckBoxMenuItem() {

    JMenu menu = new JMenu(this.getLayerName());

    menu.add(this.onCB.getMenuItem());
    menu.addSeparator();
    this.allMenu = new JMenuItem(AgentWorldModelLayer.SETS_ALL_ON_TEXT);
    this.allMenu.addActionListener(this);
    menu.add(this.allMenu);
    menu.addSeparator();
    menu.add(this.teammatesCB.getMenuItem());
    menu.add(this.nextTeammateCB.getMenuItem());
    menu.add(this.opponentCB.getMenuItem());
    menu.add(this.nextOpponentCB.getMenuItem());
    menu.addSeparator();
    menu.add(this.playerCB.getMenuItem());
    menu.add(this.bestPosCB.getMenuItem());
    menu.add(this.ballCB.getMenuItem());
    menu.add(this.ipCB.getMenuItem());
    menu.add(this.oppIPCB.getMenuItem());
    menu.add(this.velocityCB.getMenuItem());
    menu.add(this.offsideLineCB.getMenuItem());
    menu.add(this.staminaCB.getMenuItem());

    return menu;
  }

  /**
   * is called, when the menu item "Sets all ..." was clicked.
   * 
   * @param e
   *          the ActionEvent
   */
  public void actionPerformed(ActionEvent e) {

    if (this.allMenu.getText().compareTo(AgentWorldModelLayer.SETS_ALL_ON_TEXT) == 0) {
      this.teammatesCB.setSelected(true);
      this.nextTeammateCB.setSelected(true);
      this.opponentCB.setSelected(true);
      this.nextOpponentCB.setSelected(true);
      this.playerCB.setSelected(true);
      this.bestPosCB.setSelected(true);
      this.ballCB.setSelected(true);
      this.ipCB.setSelected(true);
      this.oppIPCB.setSelected(true);
      this.velocityCB.setSelected(true);
      this.offsideLineCB.setSelected(true);
      this.staminaCB.setSelected(true);
      this.allMenu.setText(AgentWorldModelLayer.SETS_ALL_OFF_TEXT);
    }
    else {
      this.teammatesCB.setSelected(false);
      this.nextTeammateCB.setSelected(false);
      this.opponentCB.setSelected(false);
      this.nextOpponentCB.setSelected(false);
      this.playerCB.setSelected(false);
      this.bestPosCB.setSelected(false);
      this.ballCB.setSelected(false);
      this.ipCB.setSelected(false);
      this.oppIPCB.setSelected(false);
      this.velocityCB.setSelected(false);
      this.offsideLineCB.setSelected(false);
      this.staminaCB.setSelected(false);
      this.allMenu.setText(AgentWorldModelLayer.SETS_ALL_ON_TEXT);
    }
  }

  /**
   * is called when a bool has changed.
   */
  public void boolChanged() {

    if (this.teammatesCB.getValue() && this.nextTeammateCB.getValue() && this.opponentCB
        .getValue() && this.nextOpponentCB.getValue() && this.playerCB
        .getValue() && this.bestPosCB.getValue() && this.ballCB.getValue() && this.ipCB
        .getValue() && this.oppIPCB.getValue() && this.velocityCB.getValue() && this.offsideLineCB
        .getValue() && this.staminaCB.getValue()) {
      this.allMenu.setText(AgentWorldModelLayer.SETS_ALL_OFF_TEXT);
    }
    else {
      this.allMenu.setText(AgentWorldModelLayer.SETS_ALL_ON_TEXT);
    }
  }

  // private LocalScene clientScene = new LocalScene();

  private float     ballMagnify;

  private float     playerMagnify;

  private boolean[] isSelected = new boolean[Param.TOTAL_PLAYER];

  public void selectSoccerObject(int id,
      boolean flag) {

    if (id >= Param.TOTAL_PLAYER) {
      return;
    }
    this.isSelected[id] = flag;
  }

  @Override
  public void draw(Graphics g) {

    if (!this.enable || this.fieldPane.getScene().time <= 0) {
      return;
    }

    this.ballMagnify = this.fieldPane.getBallMagnify();
    this.playerMagnify = this.fieldPane.getPlayerMagnify();

    Graphics2D g2 = (Graphics2D) g;
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));

    // get data for cycle we have to draw...
    ClientScene thisScene = this.fieldPane.getScene();
    for (int i = 0; i < Param.TOTAL_PLAYER; i++) {
      if (this.isSelected[i]) {
        int c = 0;
        PlayerWorldModel pwm = thisScene.player[i].getWorldModel();
        if (pwm == null) {
          continue;
        }
        while (pwm == null || pwm.positionX == -9999) {
          try {
            thisScene = WorldModel.getSceneSet().elementAt(
                this.fieldPane.getScene().time - c);
          }
          catch (IndexOutOfBoundsException e) {
            break;
          }
          pwm = thisScene.player[i].getWorldModel();
          c++;
        }
        if (pwm == null) {
          continue;
        }

        this.drawPlayers(pwm, i < Param.MAX_PLAYER, g2);

        if (true) {
          this.drawBall(pwm, g2);
        }
        if (true) {
          this.drawIP(pwm, g2);
        }
        if (this.oppIPCB.getValue()) {
          this.drawOppIP(pwm, g2);
        }
        if (true) {
          this.drawOffsideLine(pwm, g2);
        }
      }
    }

    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
  }

  private Point2f drawPoint           = new Point2f();

  private Point2f drawSize            = new Point2f();

  private Point2f drawOffset          = new Point2f();

  private Point2f upperOffside        = new Point2f();

  private Point2f lowerOffside        = new Point2f();

  private boolean showOnlyPositioning = false;

  /**
   * Returns the color for a player
   * 
   * @param player
   *          the player
   * @param leftSide
   *          true if the player play from left to right
   * @return the color
   */
  private Color getDrawColor(SimplePlayer player,
      boolean leftSide) {

    Color drawColor = Color.MAGENTA;

    if (!leftSide) {
      drawColor = Color.RED;
    }
    else {
      drawColor = Color.YELLOW;
    }

    if (player.positionIsReliable == false && !leftSide) {
      drawColor = Color.BLACK;
    }
    if (player.positionIsReliable == false && leftSide) {
      drawColor = Color.WHITE;
    }

    if (player.isGoalie && !leftSide) {
      drawColor = Color.BLUE;
    }

    if (player.isGoalie && leftSide) {
      drawColor = Color.GREEN;
    }

    return drawColor;
  }

  private void drawPlayer(SimplePlayer player,
      Graphics g,
      boolean leftSide,
      boolean next,
      int playerNumber) {

    if (this.showOnlyPositioning || player == null) {
      return;
    }

    float playerR = HeteroParam.get(player.playerType).player_size * this.playerMagnify;

    Color drawColor = this.getDrawColor(player, leftSide);
    if (next) {
      drawColor = Color.BLACK;
    }

    // draw mode
    g.setColor(Color.black);

    Point2f pos = new Point2f((float) player.positionY,
        (float) player.positionX);
    if (this.playerCB.getValue()) {
      this.fillCircle(g, pos, playerR);

      // draw body angle
      g.setColor(drawColor);
      this.drawSize.set(playerR, playerR);
      this.drawPoint.sub(pos, this.drawSize);
      this.drawSize.scale(2);
      this.fillArc(g, this.drawPoint, this.drawSize,
          -((int) player.simpleBody + 90), 180);

      // draw body
      g.setColor(drawColor);
      this.drawCircle(g, pos, playerR);

      // draw unum
      if (next) {
        g.setColor(Color.black);
      }
      else {
        g.setColor(Color.white);
      }

      if (!this.showOnlyPositioning) {
        this.drawOffset.set(0, -playerR);
        this.drawPoint.add(pos, this.drawOffset);
        this.drawString(g, Integer.toString(playerNumber), this.drawPoint);

        // draw interception time
        if (!next) {
          String interceptString = (player.ballInterceptionTime == Integer.MAX_VALUE) ? "x" : Integer
              .toString(player.ballInterceptionTime);
          g.setColor(Color.white);
          this.drawOffset.set(playerR, 0);
          this.drawPoint.add(pos, this.drawOffset);
          this.drawString(g, interceptString, this.drawPoint);
        }

        // draw playerType
        if (!next) {
          String playerTypeString = Integer.toString(player.playerType);
          g.setColor(Color.lightGray);
          this.drawOffset.set(-playerR, playerR);
          this.drawPoint.add(pos, this.drawOffset);
          this.drawString(g, playerTypeString, this.drawPoint);
        }

        // draw role number
        if (!next) {
          String roleString = (player.roleNumber < 0) ? "x" : Integer
              .toString(player.roleNumber);
          g.setColor(Color.white);
          this.drawOffset.set(0, playerR + (float) 0.3);
          this.drawPoint.add(pos, this.drawOffset);
          this.drawString(g, roleString, this.drawPoint);
        }
      }
    }
    if (this.bestPosCB.getValue()) {
      if (!next && player.bestPos != null) {
        g.setColor(Color.ORANGE);
        this.drawLine(g, pos, player.bestPos);
        g.setColor(Color.MAGENTA);
        this.fillCircle(g, player.bestPos, 0.5f);
      }
    }

    // if(!next && player.bestPos !=null){
    // String bestPosString = player.unum + " " + player.roleNumber;
    // g.setColor(Color.black);
    // drawString(g, bestPosString, player.bestPos);
    // }

    // draw predicted state
    if (next && !this.showOnlyPositioning) {
      g.setColor(Color.BLACK);
      this.drawOffset.set(playerR, 0);
      this.drawPoint.add(pos, this.drawOffset);
      String state = player.lastState == STATES.DUMMY_STATE ? "" : player.lastState
          .toString();
      if (state.length() == 0) {
        this.drawString(g, "NO STATE", this.drawPoint);
      }
      else {
        this.drawString(g, state, this.drawPoint);
      }
    }

    // draw player velocity
    if (!next && this.velocityCB.getValue()) {
      g.setColor(Color.red);
      Point2f newPos = new Point2f(pos);
      newPos.add(new Point2f((float) player.speedY, (float) player.speedX));
      this.drawLine(g, pos, newPos);
      this.drawCircle(g, newPos, playerR);
    }

    // draw stamina
    if (this.staminaCB.getValue()) {
      g.setColor(Color.black);
      Tuple2f size = new Tuple2f(playerR / 2, playerR * 2);
      Point2f drawPoint = new Point2f(pos);
      drawPoint.add(new Point2f((float) (playerR + size.getX()),
          (float) (playerR - size.getY())));
      this.fillRect(g, drawPoint, size);

      if (player.stamina > Param.STAMINA_MAX * Param.EFFORT_INC_THR) {
        g.setColor(Color.green);
      }
      else if (player.stamina > Param.STAMINA_MAX * Param.EFFORT_DEC_THR) {
        g
            .setColor(Color
                .getHSBColor(
                    (player.stamina - Param.STAMINA_MAX * Param.EFFORT_DEC_THR) / (3 * (Param.STAMINA_MAX * (Param.EFFORT_INC_THR - Param.EFFORT_DEC_THR))),
                    1.0f, 1.0f));
      }
      else {
        g.setColor(Color.red);
      }

      size.set(playerR / 2, playerR * 2 * (player.stamina / Param.STAMINA_MAX));
      this.fillRect(g, drawPoint, size);
    }
  }

  /**
   * draws all players of if they are in the player world model
   * 
   * @param pwm
   *          the player world model
   * @param leftSide
   *          true if the player ist playing on left side
   * @param g
   *          the graphical context
   */
  private void drawPlayers(PlayerWorldModel pwm,
      boolean leftSide,
      Graphics g) {

    for (int i = 0; i < Param.MAX_PLAYER; i++) {
      if (this.teammatesCB.getValue()) {
        this.drawPlayer(pwm.teammates[i], g, leftSide, false, i + 1);
      }
      if (this.nextTeammateCB.getValue()) {
        this.drawPlayer(pwm.nextTeammates[i], g, leftSide, true, i + 1);
      }
      if (this.opponentCB.getValue()) {
        this.drawPlayer(pwm.opponents[i], g, !leftSide, false, i + 1);
      }
      if (this.nextOpponentCB.getValue()) {
        this.drawPlayer(pwm.nextOpponents[i], g, !leftSide, true, i + 1);
      }
    }
  }

  private void drawBall(PlayerWorldModel pwm,
      Graphics g) {

    float ballR = Param.BALL_SIZE * this.ballMagnify;
    Point2f ballPos = new Point2f((float) pwm.ballPositionY,
        (float) pwm.ballPositionX);
    g.setColor(ColorDB.getColor("ball"));
    this.fillCircle(g, ballPos, ballR);

    // draw ball velocity
    if (true) {
      g.setColor(Color.red);
      Point2f newPos = new Point2f(ballPos);
      newPos.add(new Point2f(new Point2f((float) pwm.ballSpeedY,
          (float) pwm.ballSpeedX)));
      this.drawLine(g, ballPos, newPos);
      this.drawCircle(g, newPos, ballR);
    }
  }

  private void drawIP(PlayerWorldModel pwm,
      Graphics g) {

    float ballR = Param.BALL_SIZE * this.ballMagnify;
    g.setColor(Color.RED);
    this.fillCircle(g, new Point2f((float) pwm.ballInterceptY,
        (float) pwm.ballInterceptX), ballR);
  }

  private void drawOppIP(PlayerWorldModel pwm,
      Graphics g) {

    float ballR = Param.BALL_SIZE * this.ballMagnify;
    g.setColor(Color.BLUE);
    this.fillCircle(g, new Point2f((float) pwm.oppInterceptY,
        (float) pwm.oppInterceptX), ballR);
  }

  private void drawOffsideLine(PlayerWorldModel pwm,
      Graphics g) {

    g.setColor(Color.BLUE);

    this.upperOffside = new Point2f((float) pwm.offsideY, Param.PITCH_WIDTH / 2);
    this.lowerOffside = new Point2f((float) pwm.offsideY,
        -Param.PITCH_WIDTH / 2);

    this.drawLine(g, this.upperOffside, this.lowerOffside);
  }

}
